package main

import (
	"github.com/jinzhu/gorm"
	"github.com/pelletier/go-toml"
	_ "github.com/jinzhu/gorm/dialects/mysql"
	"flag"
	"git.apache.org/thrift.git/lib/go/thrift"
	"os"
	"log"
	"gen-go/BlogServices"
	service "service.mirchen.com/service.blog.mirchen.com"
	"fmt"
	"runtime"
	_ "net/http/pprof"
	"net/http"
	"html/template"
	"strconv"
	"os/exec"
)

var config *toml.TomlTree
var orm *gorm.DB

func init() {
	configTree, err := toml.LoadFile("config.toml")
	if err != nil {
		panic(err.Error())
	}
	config = configTree
	dbname := config.Get("database.mysql.dbname").(string)
	dbuser := config.Get("database.mysql.dbuser").(string)
	dbpass := config.Get("database.mysql.dbpass").(string)
	charset := config.Get("database.mysql.charset").(string)
	dbserver := config.Get("database.mysql.dbserver").(string)
	db, err := gorm.Open("mysql", dbuser + ":" + dbpass + "@" + dbserver + "/" + dbname + "?charset=" + charset + "&parseTime=True&loc=Local")
	if err != nil {
		panic(err.Error())
	}
	gorm.DefaultTableNameHandler = func(db *gorm.DB, defaultTableName string) string {
		//重写表名函数
		return "learn_" + defaultTableName
	}
	orm = db
	orm.SingularTable(true) //防止表名自动添加复数形式
	orm.LogMode(false)       //显示SQL日志
}
//单独出来orm不共享
func GetOrm() *gorm.DB {
	dbname := config.Get("database.mysql.dbname").(string)
	dbuser := config.Get("database.mysql.dbuser").(string)
	dbpass := config.Get("database.mysql.dbpass").(string)
	charset := config.Get("database.mysql.charset").(string)
	dbserver := config.Get("database.mysql.dbserver").(string)
	db, err := gorm.Open("mysql", dbuser + ":" + dbpass + "@" + dbserver + "/" + dbname + "?charset=" + charset + "&parseTime=True&loc=Local")
	if err != nil {
		panic(err.Error())
	}
	db.SingularTable(true) //防止表名自动添加复数形式
	db.LogMode(false)       //显示SQL日志
	return db
}

func main() {
	//启动所有的CPU
	runtime.GOMAXPROCS(runtime.NumCPU())
	//注册recover机制
	defer func() {
		//pianc
		if err := recover(); err != nil {
			fmt.Println(err)
		}
	}()
	protocol := flag.String("P", "binary", "指定协议(binary, compact, json, simplejson)")
	framed := flag.Bool("framed", false, "Use framed transport")
	buffered := flag.Bool("buffered", false, "Use buffered transport")
	addr := flag.String("addr", "0.0.0.0:9090", "监听的地址")
	flag.Parse()                                 //解析接收的所有参数
	var protocolFactory thrift.TProtocolFactory //定义数据传输协议工厂(接口类型)
	switch *protocol {
	case "binary", "":
		protocolFactory = thrift.NewTBinaryProtocolFactoryDefault() //二进制格式
	case "compact":
		protocolFactory = thrift.NewTCompactProtocolFactory() //压缩格式
	case "json":
		protocolFactory = thrift.NewTJSONProtocolFactory() //JSON格式
	case "simplejson":
		protocolFactory = thrift.NewTSimpleJSONProtocolFactory() //SimpleJSON格式
	default:
		flag.Usage() //显示命令使用手册
		os.Exit(1)
	}

	var transportFactory thrift.TTransportFactory //定义传输工厂(接口类型)
	if *buffered {
		transportFactory = thrift.NewTBufferedTransportFactory(8192) //缓存传输,写入数据后不立即传输,直到刷新缓存
	} else {
		transportFactory = thrift.NewTTransportFactory() //直接传输
	}
	if *framed {
		transportFactory = thrift.NewTFramedTransportFactory(transportFactory) //采用分块传输,依赖其他传输方式.
	}
	RunServer(protocolFactory, transportFactory, *addr)
}

func RunServer(protocolFactory thrift.TProtocolFactory, transportFactory thrift.TTransportFactory, addr string) {
	var transport thrift.TServerTransport
	var err error
	//创建socket监听
	transport, err = thrift.NewTServerSocket(addr)
	if err != nil {
		panic(err.Error())
	}
	//注册多进程服务
	tprocessors := thrift.NewTMultiplexedProcessor();
	//注册可以提供的服务
	tprocessors.RegisterProcessor("ArticleService", BlogServices.NewArticleServiceProcessor(service.NewArticleServiceHandler(GetOrm())))
	tprocessors.RegisterProcessor("MenuService", BlogServices.NewMenuServiceProcessor(service.NewMenuServiceHandler(GetOrm())))
	tprocessors.RegisterProcessor("CategoryService", BlogServices.NewCategoryServiceProcessor(service.NewCategoryServiceHandler(GetOrm())))
	tprocessors.RegisterProcessor("ConfigService", BlogServices.NewConfigServiceProcessor(service.NewConfigServiceHandler(GetOrm())))
	tprocessors.RegisterProcessor("TagService", BlogServices.NewTagServiceProcessor(service.NewTagServiceHandler(GetOrm())))
	tprocessors.RegisterProcessor("LinkService", BlogServices.NewLinkServiceProcessor(service.NewLinkServiceHandler(GetOrm())))
	//运行服务器(生成服务进程)
	server := thrift.NewTSimpleServer4(tprocessors, transport, transportFactory, protocolFactory)

	//注册客户端程序
	http.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) {
		socket, _ := thrift.NewTSocket(addr)        //建立服务socket
		transport := transportFactory.GetTransport(socket)
		var protocol thrift.TProtocol = thrift.NewTBinaryProtocolTransport(transport)
		protocol = thrift.NewTMultiplexedProtocol(protocol, "ArticleService")
		articleClient := BlogServices.NewArticleServiceClientProtocol(transport, protocol, protocol)
		err := transport.Open()
		if err != nil {
			log.Fatal("Unable to open client socket", err)
		}
		defer transport.Close()
		articles, err := articleClient.GetArticles("1=1", 0, 100)
		if err != nil {
			fmt.Fprintln(rw, err.Error())
		} else {
			info := map[string]interface{}{
				"TotalCount" : len(articles),
				"Artiles" : articles,
			}
			templ, _ := template.New("index").Parse(`
			<h1>{{.TotalCount}}篇文章</h1>
			<table style="width:100%;border:1px #ccc dotted;">
			<tr style='text-align: left'>
			  <th>#</th>
			  <th>标题</th>
			  <th>操作</th>
			</tr>
			{{range $key,$item := .Artiles}}
			<tr>
			  <td>{{$item.ID}}</td>
			  <td>{{$item.Title}}</td>
			  <td><a href='/article?id={{$item.ID}}' target='_blank'>查看</a></td>
			</tr>
			{{end}}
			</table>
			`)
			if err := templ.Execute(rw, info); err != nil {
				fmt.Fprintf(rw, err.Error())
			}
		}
	})

	http.HandleFunc("/article", func(rw http.ResponseWriter, r *http.Request) {
		socket, _ := thrift.NewTSocket(addr)        //建立服务socket
		transport := transportFactory.GetTransport(socket)
		var protocol thrift.TProtocol = thrift.NewTBinaryProtocolTransport(transport)
		protocol = thrift.NewTMultiplexedProtocol(protocol, "ArticleService")
		articleClient := BlogServices.NewArticleServiceClientProtocol(transport, protocol, protocol)
		err := transport.Open()
		if err != nil {
			log.Fatal("Unable to open client socket", err)
		}
		defer transport.Close()
		_id := r.URL.Query().Get("id")
		if _id == "" {
			fmt.Fprint(rw, "页面ID错误")
			return
		}
		id, err := strconv.Atoi(_id)
		if err != nil || id < 1 {
			fmt.Fprint(rw, "页面ID格式错误")
			return
		}
		article, err := articleClient.GetArticleById(int64(id))
		if err != nil {
			fmt.Fprintln(rw, err.Error())
		} else {
			info := map[string]interface{}{
				"Title" : article.Title,
				"Content" : template.HTML(article.Content),
			}
			templ, _ := template.New("article").Parse(`
			<h1>{{.Title}}篇文章</h1>
			<div>
			{{.Content}}
			</div>
			`)
			if err := templ.Execute(rw, info); err != nil {
				fmt.Fprintf(rw, err.Error())
			}
		}
	})

	go func() {
		defer func() {
			if err := recover(); err != nil {
				fmt.Println(err)
			}
		}()
		fmt.Println("Go Client Listen : 0.0.0.0:8081")
		if err = http.ListenAndServe(":8081", nil); err != nil {
			fmt.Println("Listen : 0.0.0.0:8081 Error : ", err)
		}
	}()
	if runtime.GOOS == "windows" {	//如果运行环境是windows 就启动8082端口
		go func() {
			//屏蔽服务端开启php程序
			fmt.Println("PHP Client Listen : 0.0.0.0:8082")
			exec.Command("php", "-S", "0.0.0.0:8082", "-t", "blog.mirchen.com").Run()
		}()
	}
	fmt.Println("Go Server Listen : " + addr)
	err = server.Serve()
	if err != nil {
		fmt.Println("Server Listen :  " + addr + " Error : ", err.Error())
	}

}



